package com.sanweibook.jhook.shiro.realm;

import com.google.common.collect.Lists;
import com.sanweibook.jhook.biz.sys.SysRoleMenuService;
import com.sanweibook.jhook.biz.sys.SysRoleService;
import com.sanweibook.jhook.biz.sys.SysUserRoleService;
import com.sanweibook.jhook.biz.sys.SysUserService;
import com.sanweibook.jhook.common.Constants;
import com.sanweibook.jhook.common.exception.JhookException;
import com.sanweibook.jhook.common.result.Result;
import com.sanweibook.jhook.common.util.JhookObjectUtils;
import com.sanweibook.jhook.common.util.SpringContextUtil;
import com.sanweibook.jhook.dal.model.sys.SysRole;
import com.sanweibook.jhook.dal.model.sys.SysRoleMenu;
import com.sanweibook.jhook.dal.model.sys.SysUser;
import com.sanweibook.jhook.dal.model.sys.SysUserRole;
import com.sanweibook.jhook.dubbo.dto.sys.SysMenuDTO;
import com.sanweibook.jhook.dubbo.dto.sys.SysUserDTO;
import com.sanweibook.jhook.dubbo.facade.sys.SysMenuFacade;
import com.sanweibook.jhook.dubbo.facade.sys.SysUserFacade;
import com.sanweibook.jhook.redis.core.RedisClientTemplate;
import com.sanweibook.jhook.shiro.util.ByteSourceUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * Created by twg on 16/10/31.
 */
@Slf4j
public class UserAuthorizingRealm extends AuthorizingRealm {
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private SysRoleService sysRoleService;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysRoleMenuService sysRoleMenuService;
    @Autowired
    private RedisClientTemplate redisClientTemplate;

    @Override
    public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Collection collection = principals.fromRealm( getName() );
        if (collection.isEmpty()) {
            throw new JhookException( "realmName must not empty." );
        }
        //登录时的用户名
        String userName = (String) collection.iterator().next();
        SysUserFacade sysUserFacade = (SysUserFacade) SpringContextUtil.getBean( "sysUserFacade" );
        Result<SysUserDTO> sysUserDTOResult = sysUserFacade.getSysUser( userName );
        if (!sysUserDTOResult.isSuccess() || sysUserDTOResult.getData() == null) {
            throw new JhookException( "用户不存在" );
        }

        SysUserDTO sysUserDTO = sysUserDTOResult.getData();
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId( sysUserDTO.getId() );
        sysUserRole = sysUserRoleService.get( sysUserRole );
        SysRole sysRole = new SysRole();
        sysRole.setId( sysUserRole.getRoleId() );
        sysRole = sysRoleService.get( sysRole );
        SysRoleMenu sysRoleMenu = new SysRoleMenu();
        sysRoleMenu.setRoleId( sysRole.getId() );
        List<SysRoleMenu> sysRoleMenus = sysRoleMenuService.queryAll( sysRoleMenu );

        List<Long> menuIds = Lists.newArrayList();
        sysRoleMenus.forEach( roleMenu -> menuIds.add( roleMenu.getMenuId() ) );

        AuthorUser authorUser = new AuthorUser();
        authorUser.setId( sysUserDTO.getId() );
        authorUser.setUserName( sysUserDTO.getUserName() );
        authorUser.setRoleName( sysRole.getRoleName() );

        SimpleAuthorizationInfo simpleAuthorizationInfo = setSimpleAuthorizationInfoAndMenu( menuIds, authorUser );
        redisClientTemplate.hSet( Constants.JHOOK_AUTHOR_USER, userName, JhookObjectUtils.objectToJson( authorUser ) );

        return simpleAuthorizationInfo;
    }


    @Override
    public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String userName = (String) token.getPrincipal();
        String password = new String( (char[]) token.getCredentials() );
        if (StringUtils.isEmpty( userName ) || StringUtils.isEmpty( password )) {
            throw new AuthenticationException( "用户名、密码不能为空" );
        }
        SysUser sysUser = new SysUser();
        sysUser.setUserName( userName );
        sysUser.setStatus( 1 );
        SysUser user = sysUserService.get( sysUser );
        if (user == null) {
            throw new AuthenticationException( "用户不存在" );
        }
        return new SimpleAuthenticationInfo( userName, user.getUserPassword(), ByteSourceUtils.bytes( userName + user.getSalt() ), getName() );
    }


    private List<Long> getFirstLevelMenuIds(List<SysMenuDTO> menuResult) {
        List<Long> parentIds = Lists.newArrayList();
        menuResult.forEach( menu -> {
            if (menu.getIsShow() == 1 && StringUtils.isBlank( menu.getMenuHref() )) {
                parentIds.add( menu.getId() );
            }
        } );
        /*for (SysMenuDTO menu : menuResult) {
            if (menu.getIsShow() == 1 && StringUtils.isBlank( menu.getMenuHref() )) {
                parentIds.add( menu.getId() );
            }
        }*/
        return parentIds;
    }

    private void addPermissions(List<SysMenuDTO> sysMenuDTOList, SimpleAuthorizationInfo simpleAuthorizationInfo) {
        List<String> rolePermissions = Lists.newArrayList();
        for (SysMenuDTO sysMenuDTO : sysMenuDTOList) {
            if (StringUtils.isNotBlank( sysMenuDTO.getPermission() )) {
                rolePermissions.add( sysMenuDTO.getPermission() );
            }
        }
        simpleAuthorizationInfo.addStringPermissions( rolePermissions );
    }

    //设置菜单权限和用户菜单
    private SimpleAuthorizationInfo setSimpleAuthorizationInfoAndMenu(List<Long> menuIds, AuthorUser authorUser) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        final SysMenuFacade sysMenuFacade = (SysMenuFacade) SpringContextUtil.getBean( "sysMenuFacade" );
        try {
            List<CompletableFuture<Result<List<SysMenuDTO>>>> sysMenuAllFuture = Lists.newArrayList();
            sysMenuAllFuture.add( CompletableFuture.supplyAsync( () -> {
                return sysMenuFacade.list( new SysMenuDTO() );
            } ) );
            List<SysMenuDTO> sysMenuAllDTOS = Lists.newArrayList();
            for (CompletableFuture<Result<List<SysMenuDTO>>> resultCompletableFuture : sysMenuAllFuture) {
                sysMenuAllDTOS.addAll( resultCompletableFuture.get().getData() );
            }

            List<CompletableFuture<Result<List<SysMenuDTO>>>> sysMenuByIdsFuture = Lists.newArrayList();
            sysMenuByIdsFuture.add( CompletableFuture.supplyAsync( () -> {
                return sysMenuFacade.listByMenuIds( menuIds );
            } ) );
            List<SysMenuDTO> sysMenuByIdsDTOS = Lists.newArrayList();
            for (CompletableFuture<Result<List<SysMenuDTO>>> resultCompletableFuture : sysMenuByIdsFuture) {
                sysMenuByIdsDTOS.addAll( resultCompletableFuture.get().getData() );
            }
            /*获取菜单权限信息*/
            addPermissions( sysMenuAllDTOS, simpleAuthorizationInfo );
            /*级联获取菜单信息*/
            List<Long> parentIds = getFirstLevelMenuIds( sysMenuByIdsDTOS );
            Result<List<SysMenuDTO>> result = sysMenuFacade.listByMenuIds( parentIds );
            if (result.isSuccess()) {
                authorUser.setSysMenus( result.getData() );
            }
        } catch (Exception e) {
            log.error( "设置菜单权限和用户菜单异常：{}", e );
            throw new JhookException( e );
        } finally {
        }
        return simpleAuthorizationInfo;
    }
}
